#ifndef GTL_AUTOMEMBER_HEADER_GUARD
#define GTL_AUTOMEMBER_HEADER_GUARD

#include "gtlCompilerSpecific.h"
#include "gtlDebug.h"

namespace GTL
{
	namespace Producer
	{
		///************************************************************************/
		///* Type Producer                                                        */
		///************************************************************************/

		typedef void*(*TypeProducer)();

		void* ProduceType(const char* name);
		void RegisterTypeProducer( const char* name, TypeProducer producer );

		#define GTL_REGISTER_PRODUCER_NEW(name, type) \
			struct ProducerRegisterer_##type \
			{ \
				int so_that_class_not_empty; \
				ProducerRegisterer_##type() : so_that_class_not_empty(42) { GTL::Producer::RegisterTypeProducer(name, &ProducerFunction); } \
				static void* ProducerFunction() { return new type; } \
			} ProducerRegistererInstance_##type;

		#define GTL_REGISTER_PRODUCER_PRODUCE(name, type) \
			struct ProducerRegisterer_##type \
			{ \
				int so_that_class_not_empty; \
				ProducerRegisterer_##type() : so_that_class_not_empty(42) { GTL::Producer::RegisterTypeProducer(name, (GTL::Producer::TypeProducer)&type::Produce); } \
			} ProducerRegistererInstance_##type;
	}

	namespace AutoMembers
	{

		/// Usage:
		///
		///	class COuter
		///	{
		///		class CInner // Note: this does not need to be a nested class to work
		///		{
		///			void PrintAddressOfOuter()
		///			{
		///				printf( "Outer is at 0x%x\n", GET_OUTER( COuter, m_Inner ) );
		///			}
		///		};
		///
		///		CInner m_Inner;
		///		friend class CInner;
		///	};
#define GTL_GET_OUTER( OuterType, OuterMember ) \
	( ( OuterType * ) ( (uint8 *)this - offsetof( OuterType, OuterMember ) ) )

		class Producible;

		class AutoMember
		{
		public:
			AutoMember();
			Producible* ParentProducible;
			AutoMember *Next, *Prev;
			AutoMember *NextPO, *PrevPO;
			AutoMember* Children;
			AutoMember* ParentMember;
			AutoMember* NextSibling;
			virtual int GetType() = 0;
			virtual int GetBaseType() { return 'auto'; };
			bool Is(int type) { return GetType() == type; }
			virtual uint32_t OnCreate() { return 0; }

			void AddAutoMemberToPostOrderList();
#ifdef GTL_DEBUG
			bool mDebugAutoMemberNotAddedToPostOrderList;
#endif
		};

		class RootAutoMember : public AutoMember
		{
			virtual int GetType() { return 'root'; }
		};

		struct MemberList
		{
			AutoMember* Head;
			AutoMember* Tail;
			bool IsPost;

			MemberList(AutoMember* h, AutoMember* t, bool post) : Head(h), Tail(t), IsPost(post) { }

			bool IsEmpty() const { return !Head || !Tail; }
			bool IsSingle() { return Head == Tail; }

			MemberList WithoutFirst_Pre() { MemberList me = *this; me.Head = me.Head->Next; return me; }
			MemberList WithoutLast_Post() { MemberList me = *this; me.Tail = me.Tail->PrevPO; return me; }

			MemberList Upto(int lim);
			MemberList From(int lim);

			static AutoMember* MakeTree(MemberList preorder, MemberList postorder);
		};

		class Producible
		{
		public:
			template <typename T>
			static T* Produce()
			{
				GTL_ASSERT(mCreatingObject == 0);

				/// Reset the creation variables
				mAutoMemberHead = mAutoMemberTail = mAutoMemberPostOrderHead = mAutoMemberPostOrderTail = 0;

				/// Allocate memory for the Producible
				mCreatingObject = (T*)(new char[sizeof(T)]);

				/// This resets the memory used by the Producibles.
				/// It's arguably better than not doing it, because it avoids
				/// errors with pointers not being initialized to zero. Might
				/// cause other problems though, but for now it's fine.
				memset(mCreatingObject, 0, sizeof(T));

				/// Create the Producible, creating any AutoMembers in it, and adding them to the lists
				mCreatingObject = new(mCreatingObject) T;

				/// Add the root AutoMember at the end of the post-order list, so that it is the container
				/// of the other AM's
				mCreatingObject->mRootAutoMember.AddAutoMemberToPostOrderList();

				/// Create the actual AutoMember tree
				mCreatingObject->mMembers = MakeTree();

				/// Run OnCreate on every AutoMember
				for (AutoMember* i=mAutoMemberHead; i; i = i->Next)
				{
					i->OnCreate();
				}

				/// Run OnCreate on the Producible
				mCreatingObject->OnCreate();

				/// Zero out the creation variables, and return the Producible
				T* temp = (T*)mCreatingObject;
				mCreatingObject = 0;
				mAutoMemberHead = mAutoMemberTail = mAutoMemberPostOrderHead = mAutoMemberPostOrderTail = 0;

				return temp;
			}

			template <typename T>
			static void Destroy(T* obj)
			{
				obj->~T();
				char* p = (char*)obj;
				delete[] p;
			}

			virtual int OnCreate() = 0;
			virtual int OnDestroy() = 0;

			virtual ~Producible() { }

			virtual const char* GetName() { return "Producible"; }

			static Producible*& GetCreatingObject() {
				return mCreatingObject;
			}

		protected:
			Producible() { }
			AutoMember* mMembers;
			RootAutoMember mRootAutoMember;

			static GTL_THREAD_LOCAL Producible* mCreatingObject;
			static GTL_THREAD_LOCAL AutoMember* mAutoMemberHead;
			static GTL_THREAD_LOCAL AutoMember* mAutoMemberTail;
			static GTL_THREAD_LOCAL AutoMember* mAutoMemberPostOrderHead, *mAutoMemberPostOrderTail;
		private:
			static AutoMember* MakeTree();

			friend class AutoMember;
		};

		//protected: a () { mMembers = mAutoMemberHead; this->OnCreate(); } 
#define GTL_DEFINE_PRODUCIBLE_OBJECT(a) \
	friend class GTL::AutoMembers::Producible; \
	typedef a self_type; \
	public: \
		virtual ~a () { this->OnDestroy(); } \
		virtual const char* GetName() { return #a; } \
		static const char* GetProducibleName(a* obj = 0) { if (!obj) return #a; else return obj->GetName(); } \
		static self_type* Produce() { return GTL::AutoMembers::Producible::Produce<self_type>(); } \
	private:
		

	}
}

/// TODO: This is also fucking awesome:
/*
/// We use __ in the name here, because this is a macro, so placing it would get us the highest
/// mStateCodeLine variable, which could be redeclared in a new state class. This way, we get to the
/// low mStateCodeLine, declared in the base State class
#define actions virtual void __StateCodeActions() { switch(this->__mStateCodeLine) { case 0 /// yes, no : at the end, so we can add it after `actions`
#define done } }

namespace Latent
{
#ifdef GTL_COUNTER
#define GTL_LATENT_COUNTER __COUNTER__
#else
#define GTL_LATENT_COUNTER __LINE__
#endif

#define MAKE_LATENT(what) \
	do { what; state=GTL_LATENT_COUNTER; return; case GTL_LATENT_COUNTER:; } while (0)

#define Sleep(i) MAKE_LATENT( { printf("Sleeping for %i\n", i); } )
#define Yield() MAKE_LATENT( { printf("Yielding\n"); } )
}

struct AState : public LatentExecuter
{
  actions:
    printf("Doing something\n");
    Sleep(50);    
    printf("Doing something other\n");
		done
};
*/

#endif